package org.apache.sad.core.framework.jaxrpc;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

import javax.xml.rpc.handler.soap.SOAPMessageContext;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlOptions;

import org.apache.sad.core.framework.utils.ObfuscationUtil;

/**
 * Provides convenient methods to handle soap message, soap
 * fault etc.
 */
public class SoapUtil {
	private static Log log = LogFactory.getLog(SoapUtil.class);
	
    private static final int BUFFER_SIZE = 1024;
    private static final byte[] NEW_LINE_BYTE = new byte[] {10};
    private static final int PRETTY_PRINT_INDENT = 4;	
    
    public static String soapMessageToXml(SOAPMessageContext context) {
    	return soapMessageToObfuscatedXml(context, new String[0]);
    }
    
    public static String soapMessageToObfuscatedXml(SOAPMessageContext context, String[] obfuscatedFields) {
        SOAPMessage msg = context.getMessage();
        
    	ByteArrayOutputStream bytes = new ByteArrayOutputStream(BUFFER_SIZE);
    	byte[] soapMessageAsByteArray = null;
    	
        try {        	
        	if (context.getMessage().countAttachments() > 0) {
        		return new String(convertSOAPMessageToByteArray(msg));
        	}
        	
            XmlOptions opts = new XmlOptions();
            opts.setSavePrettyPrint();
            opts.setSavePrettyPrintIndent(PRETTY_PRINT_INDENT);
            soapMessageAsByteArray = convertSOAPMessageToByteArray(msg);
            XmlObject xo = convertSOAPMessageToXmlObject(soapMessageAsByteArray);
            bytes.write(ObfuscationUtil.obfuscateXmlString(xo.xmlText(opts), obfuscatedFields).getBytes());
            bytes.write(NEW_LINE_BYTE);
            return bytes.toString();
        } catch (Exception ex) {
        	log.warn("Unable to convert SoapMessage to pretty printed XML due to: " + ex.getMessage(), ex);
        	if ( soapMessageAsByteArray != null ) {
        		return new String(soapMessageAsByteArray);
        	}
        	return null;
        } finally {
        	try {
				bytes.close();
			} catch (IOException e) {
			}
        }
    }
    
    private static XmlObject convertSOAPMessageToXmlObject(
			byte[] soapMessageAsByteArray) throws SOAPException, IOException,
			XmlException {
		ByteArrayInputStream inputbytes = new ByteArrayInputStream(soapMessageAsByteArray);
		XmlObject xo = XmlObject.Factory.parse(inputbytes);
		return xo;
	}

	private static byte[] convertSOAPMessageToByteArray(SOAPMessage soapMessage) throws SOAPException, IOException {
		ByteArrayOutputStream outbytes = new ByteArrayOutputStream();
		soapMessage.writeTo(outbytes);
		return outbytes.toByteArray();
	}
	
	public static long getMessageSize(SOAPMessage soapMessage){
		
		try {
			ByteArrayOutputStream outbytes = new ByteArrayOutputStream();
			soapMessage.writeTo(outbytes);
			return outbytes.toByteArray().length;
		} catch (Exception e) {
			log.error("Exception while finding the lenght of SOAP message: " + e.getMessage());
			return 0;
		} 
		
	}
}
